home *** CD-ROM | disk | FTP | other *** search
/ Aminet 23 / Aminet 23 (1998)(GTI - Schatztruhe)[!][Feb 1998].iso / Aminet / docs / misc / Monster.lha / Monster.txt
Text File  |  1997-11-20  |  11KB  |  224 lines

  1. Origin: GREMLiNS BBS ...in Australia! One hell of a BBS...! ;)
  2. ****************************************************************************
  3.  
  4. Creating a Monster - My last 2 years of coding animation formats.
  5.  
  6. By Olly Koenders 14-08-97.
  7.  
  8.  
  9. Preface
  10. -------
  11.  
  12. Why am I writing this?  Umm...  No real reason, but what the heck eh?
  13.  
  14.  
  15. In the Beginning
  16. ----------------
  17.  
  18. It started as a faint glimmer in my all so feeble mind, that after coding
  19. in assembler since about 1990, after a fruituitous but very sloooow several
  20. months learning the Amiga in AmigaBasic of all things, It dawned on me that
  21. I STILL hadn't done anything with pictures - let alone ever having actually
  22. got one to display on the screen!  Shit - I didn't know what bitplanes were
  23. or how an IFF picture was coded, never mind decoding it even!  I'd gotten
  24. nowhere in a second flat, and if I hadn't found some explanatory stuff in
  25. one of my old abacus manuals (in BASIC - Ughhh!), I'd still be drawing
  26. gadgets and stuff with DrawBorder() and PrintIText().
  27.  
  28. I started pandering around with Intuition (you know, that big library
  29. tucked away in your ROM somewhere), and found a routine called DrawImage(),
  30. that I hoped would lead me on the right track.
  31.  
  32. How right I was, but still so far to go.  After fumbling around through the
  33. "includes" and "structures" listed on my VERY old Assempro disk that I
  34. never used (assempro is a BASTARD to use!), I managed to summise some things
  35. about the structure I needed for DrawImage(), although many clues were still
  36. missing.  Endless hours (days more like it) of reading my old and tattered
  37. Abacus assembler manuals, coding, crashing, re-coding (and re-crashing), I
  38. finally had it.  I got an image onto the Workbench screen in its own window
  39. and was grinning from one ear to the other!
  40.  
  41. What the image was exactly I can't remember, but I thought this was the
  42. start of a beautiful thing and stuck with it for some more days,
  43. experimenting and such forth.  I got an old routine I coded ages before to
  44. scroll some text and drew a picture (4 colours), added a protracker routine
  45. (that was pretty shithouse but still worked) and a song that I chucked
  46. together from a sampled radio tune.  I now had a small "intro" thingy with
  47. a static picture.
  48.  
  49. All well and good.  But after a couple more days of thinking I thought I
  50. thunk that I could animate this bugger.  But once I got some more ideas
  51. that "intro" went by the wayside (to a friend with some proud and boasting
  52. text!) and I cobbled together some sort of animation by changing logical
  53. addresses and displaying these images sequentially.
  54.  
  55. It was at this time I experienced problems with reliable timing between
  56. each frame, trying several things like a few WaitTOF() instructions (wait
  57. for top-of-frame) and that was the bees knees for some time.
  58.  
  59. Eventually I had smallish 160 x 128 16 colour "animation" on its own screen
  60. fumbling around displaying a cross between a Ferrari F40 and something from
  61. Back to the Future, whooshing off the screen and looping until I thumped
  62. the mouse.  Damn I was proud!  12 frames/sec on a beefed 14 mhz A500 was
  63. moving pretty well for frames that size I thought.
  64.  
  65. Then came the point where I realised that if I added more frames, the whole
  66. thing would get pretty big.  I had to devise a compression routine that
  67. could decompress these frames fast enough.  I came up with a simple but
  68. very effective byte-run algorithm and took it from there, although the
  69. playback speed suffered a bit (crawl!).
  70.  
  71. More experimentation showed that if I didn't have to decompress an entire
  72. frame each time, then the bugger would run faster and use somewhat less
  73. room as well.  I furiously coded a routine that would compare a frame with
  74. the previous, mask out the identical ones with nulls and save the resulting
  75. data to a file.  The main problem was that when it came to a null byte that
  76. wasn't originally a null, it would cause spots and lines in the frame while
  77. animating.  I sort of solved this by making a program that would check for
  78. the minimum-used byte and then substitute that for the null, then
  79. re-instate the null on playback.  This reduced the spots somewhat - but was
  80. far from ideal.  "Ferrari" is my first animation coded this way and the
  81. problems can be clearly seen.
  82.  
  83. The next problem was flickering of the image as it was drawn on the screen,
  84. as the blitter chip was too slow for larger images.  I solved that with a
  85. technique called "Double-Buffering", where you actually have 2 separate
  86. screens that you draw images on and while one is being viewed, the other is
  87. rather hastily drawn, then it's flicked to the front to be viewed and
  88. so-on (it took me absolutely AGES to find out what Double-Buffering
  89. meant!).  "CompSex" was done that way, as the images were getting too big to
  90. be displayed without flickering.  With smaller images I turned to waiting
  91. for the raster beam to reach a certain position (102 I think) before I did
  92. the DrawImage() thing.
  93.  
  94. This worked well for some time, and I produced many animations this way,
  95. some small, some a bit bigger, but the more complex the picture or more
  96. changes from one picture to the next, the more data the picture had, and
  97. the less speed I was getting.  I also wanted to make full-screen animations,
  98. but blitting an entire 320 x 256 32 colour picture to a screen with a window
  99. was almost impossible, as I was only getting about 5 frames/sec that way.
  100.  
  101. To go any further forward meant an entire re-code of ALL my
  102. compression/decompression and screen drawing routines.  I mulled it over
  103. and was so damn reluctant as it meant undoing all my hard work.  Days
  104. mulled into a couple of weeks, and finally I had a plan...
  105.  
  106. Hard Time
  107. ---------
  108.  
  109. I had a goal - to make my anim format smaller than ANIM5 and hopefully
  110. faster, but that was to be some time away.  I experimented with routines to
  111. push a picture direct to the screen bitplanes and took it from there.  How
  112. many times did I end up with picture data all over the screen (and even
  113. screens that weren't related to the one I wanted!) without the picture
  114. looking like it should have.  Eventually, I had it and found that it was
  115. possible.
  116.  
  117. Not knowing how the hell ANIM5 format was coded, or being able to find some
  118. documentation on this anywhere, I started coding a routine that would take a
  119. picture and slice it up into 8 x 8 pixel "chunks" for each bitplane, and
  120. saving those chunks into sequential bytes.  Once I had all the pictures
  121. coded I would then load up each one and compare it with the previous, and
  122. code special control bytes into it telling me what I did with this 8 x 8
  123. pixel chunk, either I byte-run compressed it as much as possible or it's
  124. just a direct dump to screen.  A code "$03" would tell me that I would have
  125. to dump all the next 8 bytes to the screen, whereas a code "$05" means that
  126. all the next 8 bytes are nulls and missing from the data, so I just dump 8
  127. null bytes to their respective places on the screen.
  128.  
  129. All the "chunks" of picture data that were the same from the previous were
  130. tallied up as "skip" chunks and weren't saved to the resulting frame file,
  131. and the number of these chunks to skip on the screen followed a "$02" for a
  132. short skip (1 - 255 chunks) or a "$01" for long skip (256 - 65535 chunks).
  133.  
  134. For a frame that doesn't change from the previous, a single null byte is
  135. used as a code saving heaps of space.
  136.  
  137. The first frame was saved out in its entirety coded in 8 x 8 pixel chunks
  138. and straight byte-run compressed.  This frame then forms the starting
  139. picture where only the changes for the next frame are drawn on etc.
  140.  
  141. Now that I didn't have to decompress an entire frame and blit the lot to
  142. the screen I had a foundation for heaps more speed, as I would only have to
  143. write the changes directly to the screen while they were being decoded.
  144.  
  145. I also didn't have to employ any sort of Double-Buffering as the chunks are
  146. drawn on the screen faster than the raster beam can pass them, so chip
  147. memory is saved by only having one screen.  If I wrote all the chunks to the
  148. screen for an entire bitplane, and then again for the next bitplane, the
  149. anim would suffer from flickering when the frames got bigger.
  150.  
  151. After lots more fooling around I finally had an entire routine that could
  152. push out an animation with frame sizes ranging from 8K to 15K on a chip
  153. only A500 with bare 68000 at around 6.5 frames sec in 32 colours.  Whoosh?
  154.  
  155. Faster and Faster...
  156. --------------------
  157.  
  158. This served me well for about the next year (!), and I learned tricks like
  159. re-mapping pictures to produce less frame data so that they playback faster,
  160. and enlarging frames on the fly so that an 80 x 64 x 32 colour frame would
  161. be seen as a 160 x 128 size frame with pixels at 2 x 2.
  162.  
  163. These routines weren't too OS friendly as they were written and tested on a
  164. KS 1.3 A500, where each bitplane for a screen was allocated by the system
  165. in a sequential fashion, so I was writing to contiguous memory.  Something
  166. changed however with the introduction of the AGA chipset and this is no
  167. longer the case.  After loading a couple of programs that use chipmem, the
  168. bitplane addresses are no longer one after the other.  This is the main
  169. problem I wanted to fix but came across some other ideas at the same time.
  170.  
  171. I got to the point where I needed something faster, as I FINALLY found some
  172. documentation on ANIM5 - not much help now, as it's done something
  173. different like coding in 8 x 256 chunks for a 256 high picture, and then
  174. all these chunks are done for one entire bitplane, then done for the next
  175. bitplane until everything's coded.  This is where Double-Buffering's
  176. needed as the flickering would be almost unbearable.  In some cases ANIM5 is
  177. a smaller format but not too often, as some DLTA tables are saved with the
  178. resulting frame and a picture same as previous has a header chunk with
  179. containing a couple of hundred bytes.
  180.  
  181. I used to decode a frame with all the screen addresses for writing to
  182. calculated in realtime, and all this overhead was pretty damn slow, so I
  183. decided to use something called a "lookup table".  This contains previously
  184. calculated screen addresses for each chunk.  All the decoding routine has to
  185. do now is grab the address from the table, and decode a chunk directly to
  186. that address, rather than calculate the address on the fly before decoding.
  187.  
  188. A 320 x 256 32 colour frame only needs 25600 bytes of table and this table
  189. is used for every frame, thereby saving memory too.
  190.  
  191. This has resulted in a 100% speed increase and is a whole frame/sec faster
  192. than PPAnim with ANIM5.
  193.  
  194. I also changed the enlarging routine to use a table for converting 16
  195. pixels to 32 and the speed increase speaks for itself.
  196.  
  197. Summary
  198. -------
  199.  
  200. Chip only A500 68000 with 320 x 256 32 colour 8 to 15K frames:
  201.  
  202.  
  203. Byterun decompress + DrawImage() frames/sec: Don't even ask!
  204.  
  205. Chunk + calculation: 6.5 frames/sec.
  206.  
  207. Chunk only (now): 12.5 frames/sec.
  208.  
  209.  
  210. Chip only A500 68000 with 80 x 64 32 colour frames (enlarging to 160 x 128):
  211.  
  212.  
  213. Byterun decompress + DrawImage() frames/sec: Didn't have one.
  214.  
  215. Chunk + calculation: 16.5 frames/sec.
  216.  
  217. Chunk only (now): 30.5 frames/sec.
  218.  
  219.        __
  220.       ///
  221.  __  ///
  222.  \\\///
  223.   \XX/  Olly '97  8)
  224.